#include "networkavdataread.h"

#include "audiotask.h"
#include "synchronousav.h"
#include "videotask.h"
#include <QDebug>
int decode_interrupt_cb(void *ctx)
{
    return *((int*)ctx);
}
//Callback
int read_buffer(void *opaque, uint8_t *buf, int buf_size)
{
   return ((NetworkAvDataRead*)opaque)->RecvBuffer(buf,buf_size);
}
int NetworkAvDataRead::RecvBuffer(uint8_t *buf, int buf_size)
{
    if(bExit)
        return 0;

    while(true)
    {
        if(m_InPut_buf.size() >= buf_size)
        {
            memcpy(buf,m_InPut_buf.data(),buf_size);
            m_InPut_buf = std::string(m_InPut_buf.begin()+ buf_size,m_InPut_buf.end());
            return buf_size;
        }

        std::string str ="";
        while(getq(str))
        {
            if (str.size() == 0)
            {
                return 0;
            }
            m_InPut_buf.append(str);
            break;
        }
    }
    return 0;
}

bool NetworkAvDataRead::receive_handler(char *data, int size)
{
    putq(std::string(data,size));
    return true;
}

NetworkAvDataRead::NetworkAvDataRead(MainWindow &w)
{
    av_register_all();

    avformat_network_init();

    pFormatCtx = avformat_alloc_context();

    pFormatCtx->interrupt_callback.callback = decode_interrupt_cb;

    pFormatCtx->interrupt_callback.opaque   = &bExit;

    aviobuffer=(unsigned char *)av_malloc(32768);

    AVIOContext *avio =avio_alloc_context(aviobuffer, 32768,0,this,read_buffer,NULL,NULL);//考虑这里会内存泄露不

    pFormatCtx->pb=avio;

    m_pWnd = &w;

    nWidth  = 0;

    nHeight = 0;
}

NetworkAvDataRead::~NetworkAvDataRead()
{
    avformat_network_deinit();

    av_close_input_file(pFormatCtx);

    pFormatCtx = NULL;
}

int NetworkAvDataRead::svc()
{
    qDebug(QString("000000000").toLocal8Bit().data());
    int err_code;
    bExit = 0;
    nWidth  = 0;
    nHeight = 0;

    if ((err_code = avformat_open_input(&pFormatCtx, NULL, NULL, NULL)) != 0)
    {
        qDebug(QString(" avformat_open_input err ......").toLocal8Bit().data());
        printf("\n");
    }

    qDebug(QString(" av_find_stream_info 2222 ......").toLocal8Bit().data());
    if((err_code = av_find_stream_info(pFormatCtx))<0)
    {
        qDebug(QString(" av_find_stream_info err ......").toLocal8Bit().data());

    }
     qDebug(QString(" av_find_stream_info yes ......").toLocal8Bit().data());
    AVCodec        *pCodecV     =NULL;
    AVCodec        *pCodecA     =NULL;

    AVStream       *AVStreamV   = NULL;
    AVStream       *AVStreamA   = NULL;

    AVCodecContext *pCodecCtxV  = NULL;
    AVCodecContext *pCodecCtxA  = NULL;

    int     video_index = -1;

    int     audio_index = -1;

    int i;

    for (i = 0; i < pFormatCtx->nb_streams; i++)
    {
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            pCodecCtxV= pFormatCtx->streams[i]->codec;

            AVStreamV = pFormatCtx->streams[i];

            pCodecV = avcodec_find_decoder(pCodecCtxV->codec_id);

            if (pCodecV && (avcodec_open2(pCodecCtxV, pCodecV,NULL) >= 0))
            {
                video_index = i;
            }
        }

        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO )
        {
            pCodecCtxA= pFormatCtx->streams[i]->codec;

            AVStreamA = pFormatCtx->streams[i];

            pCodecA = avcodec_find_decoder(pCodecCtxA->codec_id);

            if (pCodecA && (avcodec_open2(pCodecCtxA, pCodecA,NULL) >= 0))
            {
                audio_index = i;
            }
        }
    }
    nWidth  = AVStreamV->codec->width;

    nHeight = AVStreamV->codec->height;

    qDebug(QString("width  :").append(QString::number((long)nWidth)).toLocal8Bit().data());

    qDebug(QString("nHeight  :").append(QString::number((long)nHeight)).toLocal8Bit().data());

    AudioTask *  pAudioTask = new AudioTask(AVStreamA,pCodecA);

    SynchronousAV * pSynchronous = new SynchronousAV(pAudioTask,m_pWnd);    //同步音视频

    pSynchronous->setExit(false);

    VideoTask *pVideoTask =new VideoTask(pSynchronous,AVStreamV);

    pVideoTask->activate(); //启动任务  解码 视频

    //
    AVPacket *packet=(AVPacket *)malloc(sizeof(AVPacket));

    av_init_packet(packet);

    while(true)
    {
        int ret = av_read_frame(pFormatCtx, packet);

        if(ret >= 0)
        {
           if(packet->stream_index==video_index)    //视频
           {
               if(pVideoTask)
                   pVideoTask->appendVideoPacket(*packet);

           }else if(packet->stream_index==audio_index)//音频
           {
               if(pAudioTask)
                   pAudioTask->appendAudioPacket(*packet);
           }
        }else
        {
            if(ret == AVERROR_EOF)
            {
                qDebug(QString("ret == AVERROR_EOF").toLocal8Bit().data());
                 break;
            }
           //usleep(1*1000); //暂停一会儿 1毫秒
        }
    }
    av_free_packet(packet);

    pSynchronous->setExit(true);

    qDebug(QString(" pSynchronous->setExit(true)").toLocal8Bit().data());

    pVideoTask->close();

    qDebug(QString(" pVideoTask->close();").toLocal8Bit().data());

    delete pVideoTask;

    pVideoTask = NULL;

    qDebug(QString(" zzzzzzzzzzzzzzzzzzzzzz").toLocal8Bit().data());

    delete pSynchronous;

    pSynchronous = NULL;

    delete pAudioTask;

    pAudioTask = NULL;

    qDebug(QString(" xxxxxxxxxxxxxxxxx").toLocal8Bit().data());

    avcodec_close(pCodecCtxV);

    pCodecCtxV = NULL;

    avcodec_close(pCodecCtxA);

    pCodecCtxA = NULL;

    qDebug(QString("ret == end").toLocal8Bit().data());
}

int NetworkAvDataRead::close()
{
    bExit = 1; //退出

    std::string str("");

    int nthread  =thr_count();

    for (int i =0 ;i<nthread ;i++)
        putq(str);

    wait();
    qDebug(QString("111111111").toLocal8Bit().data());

    nWidth  = 0;

    nHeight = 0;
}

